package com.xianrenit.xianrenpuzi.manager.interceptor;

import com.alibaba.fastjson.JSON;
import com.xianrenit.xianrenpuzi.common.handler.exception.SpzxException;
import com.xianrenit.xianrenpuzi.common.util.consts.SpzxConst;
import com.xianrenit.xianrenpuzi.common.util.utils.ThreadLocalUtil;
import com.xianrenit.xianrenpuzi.model.entity.sys.SysUser;
import com.xianrenit.xianrenpuzi.model.result.ResultCodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class SpzxLoginAuthInterceptor implements HandlerInterceptor {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    //Threadlocal: 线程本地变量(每个线程对象的成员变量都是私有的，其他线程不能访问)
    //Map共享登录状态数据 透传给后续的业务使用
    //键：使用当前线程对象，值：使用SysUser
    //ConcurrentHashMap性能比Hashtable好，但是仍然存在并发竞争
//    public static ConcurrentHashMap<Thread, SysUser> SYS_USERS_MAP = new ConcurrentHashMap();
    public static ThreadLocal<SysUser> THREAD_LOCAL = new ThreadLocal();
    //放行前拦截请求
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //区分是预检还是正常请求，正常请求进行登录校验
        //预检请求直接放行
        String method = request.getMethod();
        if("OPTIONS".equals(method.toUpperCase())){
            return true;
        }
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            throw new SpzxException(ResultCodeEnum.LOGIN_STATUS_ERROR);
        }
        //查询redis中的登录状态数据
        String json = stringRedisTemplate.opsForValue().get(SpzxConst.LOGIN_USER_KEY_PREFIX + token);
        if(StringUtils.isEmpty(json)){
            throw new SpzxException(ResultCodeEnum.LOGIN_STATUS_ERROR);
        }
        //缓存登录状态共享给后续的业务使用
        //request域共享数据
        //也可以使用内存共享：Map<String,SysUser>  ConcurrentHashMap
        //token: 每个用户唯一的登录状态 token ，但是后面后去map中的数据时还需要获取token然后再查询数据
//        Thread.currentThread(); 当前线程对象

//        SYS_USERS_MAP.put(Thread.currentThread() , JSON.parseObject(json,SysUser.class));
        //使用线程对象的threadLocalMap存储:key为THREAD_LOCAL对象，值为传入的数据
        THREAD_LOCAL.set(JSON.parseObject(json,SysUser.class));
        ThreadLocalUtil.set(JSON.parseObject(json,SysUser.class));
        //放行请求
        return true;
    }
    //controller执行后调用
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //收尾操作
        //清空不在使用的登录缓存: 内存泄露
//        SYS_USERS_MAP.remove(Thread.currentThread());
        THREAD_LOCAL.remove();
        ThreadLocalUtil.remove();
    }
}
